﻿using System;
using System.Collections.Generic;

namespace Nomo.CoreModule
{
    /// <summary>
    /// 为网格图提供工具方法。
    /// </summary>
    public static class GridMapHelper
    {
        /// <summary>
        /// 获取二维数组在指定的行列坐标处的成员的某个方向的邻居。
        /// </summary>
        /// <param name="array">二维数组。</param>
        /// <param name="rowIndex">行坐标。二维数组第一维的坐标。</param>
        /// <param name="columnIndex">列坐标。二维数组第二维的坐标。</param>
        /// <param name="direction">方向。允许传入 <see cref="Direction.None"/> .</param>
        /// <param name="result">如果发生了异常，则为 <typeparamref name="T"/> 的默认值。</param>
        /// <typeparam name="T">二维数组成员的类型，它必须是一个引用类型。</typeparam>
        /// <returns>二维数组在指定的行列坐标处的成员的某个方向的邻居。</returns>
        /// <exception cref="ArgumentNullException"><paramref name="array"/> 为 <see langword="null"/> .</exception>
        public static bool TryGetNeighbor<T>(T[,] array, int rowIndex, int columnIndex, Direction direction, out T result) where T : class
        {
            if (array == null)
            {
                throw new ArgumentNullException(nameof(array));
            }
            try
            {
                switch (direction)
                {
                    case Direction.None:
                        result = array[rowIndex, columnIndex];
                        break;
                    case Direction.Up:
                        result = array[rowIndex - 1, columnIndex];
                        break;
                    case Direction.Left:
                        result = array[rowIndex, columnIndex - 1];
                        break;
                    case Direction.Down:
                        result = array[rowIndex + 1, columnIndex];
                        break;
                    case Direction.Right:
                        result = array[rowIndex, columnIndex + 1];
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(direction), direction, null);
                }
                return true;
            }
            catch
            {
                result = default;
                return false;
            }
        }

        /// <summary>
        /// 获取二维数组在指定的行列坐标处的成员的所有邻居。
        /// </summary>
        /// <param name="array">二维数组。</param>
        /// <param name="rowIndex">行坐标。二维数组第一维的坐标。</param>
        /// <param name="columnIndex">列坐标。二维数组第二维的坐标。</param>
        /// <typeparam name="T">二维数组成员的类型，它必须是一个引用类型。</typeparam>
        /// <returns>二维数组在指定的行列坐标处的成员的所有邻居。</returns>
        /// <exception cref="ArgumentNullException"><paramref name="array"/> 为 <see langword="null"/> .</exception>
        public static IEnumerable<T> GetNeighbors<T>(T[,] array, int rowIndex, int columnIndex) where T : class
        {
            if (array == null)
            {
                throw new ArgumentNullException(nameof(array));
            }
            if (TryGetNeighbor(array, rowIndex, columnIndex, Direction.Up, out var up))
            {
                yield return up;
            }
            if (TryGetNeighbor(array, rowIndex, columnIndex, Direction.Left, out var left))
            {
                yield return left;
            }
            if (TryGetNeighbor(array, rowIndex, columnIndex, Direction.Down, out var down))
            {
                yield return down;
            }
            if (TryGetNeighbor(array, rowIndex, columnIndex, Direction.Right, out var right))
            {
                yield return right;
            }
        }
    }
}
